home *** CD-ROM | disk | FTP | other *** search
- /*
-
- sbinder.hpp
- 10-25-91
- Streamable Binder: Loose Data Binder v 1.5
-
- Copyright 1991
- John W. Small
- All rights reserved
-
- PSW / Power SoftWare
- P.O. Box 10072
- McLean, Virginia 22102 8072 USA
-
- John Small
- Voice: (703) 759-3838
- CIS: 73757,2233
-
- */
-
-
- #ifndef SBINDER_HPP
- #define SBINDER_HPP
-
- #include <iostream.h>
- #include <iomanip.h>
-
- #ifndef BINDER_HPP
- #include "binder.hpp"
- #endif
-
- #define ID_Streamable 0
- #define ID_StreamableRef ID_Streamable
- #define ID_SBinder 1
-
-
- class Streamable;
- typedef Streamable * StreamablE;
- #define StreamablE0 ((StreamablE)0)
-
- class StreamableClassRegistry;
- #define SCRegistry SCReg
- extern StreamableClassRegistry SCRegistry;
-
- /*
-
- A class must include the STREAMABLE macro or its
- equivalent in its public section and be derived
- either publicly or privately from Streamable but
- never virtually or otherwise multiply inherited
- in order for it to be "streamable". Furthermore
- it must have been linked to. The SBinder
- primitives automatically link to and unlink from
- Streamable nodes. That means the SBinder must
- itself be linked before it can be streamed. See
- SBinder below or CBinder for an example without
- using the STREAMABLE macro and SData for an
- example using STREAMABLE.
-
- */
-
- class Streamable {
- friend StreamableClassRegistry;
- voiD parenT;
- unsigned id;
- unsigned refCount, streamCount;
- long streamPos;
- /*
- Stream contents:
-
- 1st & Only 1st of Many MultiRef
-
- id x x 0
- refCount 1 > 1
- streamCount
- streamPos x
- user's data x x
- */
- protected:
- // Static so that the static load() can call!
- static void lserror(const char *msg, unsigned id);
- virtual void serror(const char *msg);
- virtual void swarn(const char *msg);
- virtual ostream& store(ostream& os)
- { return os; }
- // Override to store your data members!
- static StreamablE load(istream& is,
- StreamablE InstancE);
- // Override - see documentation or hack it
- // from SBinder::load, SData::load, or
- // CBinder::load!
- void setID(unsigned id)
- { this->id = id; }
- public:
- static int refDebug;
- static int streamDebug;
- static char memberTermChar;
- enum { ID_CLASS = 0 };
- // The first parameter below, "dummy", insures that
- // the STREAMABLE macro defines a unique constructor
- // for derived classes!
- Streamable(StreamableClassRegistry& dummy,
- unsigned id = Streamable::ID_CLASS);
- static void registerClass(unsigned id = ID_CLASS,
- StreamablE (*loader)(istream& is,
- StreamablE InstancE) = load);
- operator StreamablE() { return this; }
- voiD ParenT() { return parenT; }
- unsigned ID() { return id; }
- virtual unsigned restream();
- unsigned unlink(voiD P = voiD0);
- StreamablE link(voiD P = voiD0);
- unsigned RefCount() { return refCount; }
- virtual ~Streamable() {}
- };
-
-
- // stream manipulator: insert end of member field char
-
- extern ostream& endm(ostream& os);
-
- // stream manipulator: extract end of member field char
-
- extern istream& nextm(istream& is);
-
-
- /*
- The STREAMABLE macro declares two functions: store()
- and load() which you must define to store member
- data onto a stream and to load that data back from
- that stream. You must assign a unique id to each
- streamable class and register every class that will
- be stored on a stream. Don't forget to restream()
- between operations!
- */
-
- #define STREAMABLE(class, id, base) \
- private: \
- friend StreamableClassRegistry; \
- protected: \
- base :: lserror; \
- base :: serror; \
- base :: swarn; \
- virtual ostream& store(ostream& os); \
- static StreamablE load(istream& is, \
- StreamablE InstancE); \
- base :: setID; \
- public: \
- enum { ID_CLASS = id }; \
- class (StreamableClassRegistry& dummy, \
- unsigned cid = class ::ID_CLASS) \
- : base (dummy,cid) {} \
- operator StreamablE() \
- { return (StreamablE)this; } \
- static void registerClass(unsigned cid = \
- class ::ID_CLASS, \
- StreamablE (*loader)(istream& is, \
- StreamablE InstancE) = class ::load) \
- { base :: registerClass(cid,loader); } \
- base :: ParenT; \
- base :: ID; \
- base :: restream; \
- base :: unlink; \
- base :: link; \
- base :: RefCount
-
-
- // value for dummy parameter of constructor above
-
- #define UNIQUE_STREAMABLE SCRegistry
-
-
- /*
- SBinder nodes MUST be derived from Streamable,
- e.g. SData, since Dfree(), Dattach(), and Ddetach()
- have been overriden to handle Streamable nodes.
- Besides adding streamability to a Binder and its
- nodes, Streamable nodes have built in protection
- against accidental deletion even when the
- BDR_OK_FREE flag is set since Streamable decendents
- report to SBinder::Dfree() if it's okay to delete.
- Streamable nodes are only stored once in any single
- streaming operation while multiple references when
- encountered are stored simply as that, multiple
- references. When reloading, multiple references to
- nodes are automatically reconstructed as links.
- This arrangement prevents storing a multiply
- referenced node multiple times on a stream and
- subsequently reloading multiple copies instead of
- correctly reconstructing the links. Consider a
- SBinder that contains nodes, some of which may be
- SBinders themselves, perhaps rereferencing other
- data nodes and it should be apparent to you why
- multiple reference streaming to necessary. It is
- also possible to have a otherwise streamable SBinder
- binding nodes not derived from Streamable, see
- CBinder.
-
- The SBinder header may be statically or dynamically
- allocated. The nodes must all be either static or
- dynamic as indicated by the BDR_OK_FREE flag.
- SBinder defaults to dynamically allocated nodes.
- */
-
- class SBinder : public Binder, public Streamable {
- protected:
- // Binder::construct
- virtual int Dfree(voiD D);
- virtual int Dattach(voiD D);
- virtual void Ddetach(voiD D);
- virtual ostream& store(ostream& os);
- static StreamablE load(istream& is,
- StreamablE InstancE);
- virtual void Dstore(ostream& os, voiD D);
- /*
- Stores node data on the stream. It
- assumes that nodes are derived from
- Streamable. If not you must
- override!
- */
- virtual voiD Dload(istream& is);
- // Loads node data back from stream.
- public:
- enum { ID_CLASS = ID_SBinder };
- SBinder(StreamableClassRegistry& dummy,
- unsigned id = ID_CLASS)
- : Binder(OnlyInitBinderVFT),
- Streamable(dummy,id) {}
- SBinder(unsigned flags = BDR_OK_FREE,
- unsigned maxNodes = BDR_MAXNODES,
- unsigned limit = BDR_LIMIT,
- unsigned delta = BDR_DELTA)
- : Binder(flags,maxNodes,limit,delta),
- Streamable(UNIQUE_STREAMABLE,ID_CLASS)
- {}
- SBinder(voiDV argv, int argc = 0,
- unsigned flags = BDR_OK_FREE)
- : Binder(argv,argc,flags),
- Streamable(UNIQUE_STREAMABLE,ID_CLASS)
- {}
- static void registerClass(unsigned id = ID_CLASS,
- StreamablE (*loader)(istream& is,
- StreamablE InstancE) = load)
- { Streamable :: registerClass(id,loader); }
- virtual unsigned restream();
- virtual ~SBinder();
- };
-
- typedef SBinder * SBindeR;
- #define SBindeR0 ((SBindeR)0)
-
-
-
- /*
-
- The StreamableClassRegistry holds the records of
- classes and their static load functions. Load
- functions have to be static because constructors
- don't have addresses in C++. Store functions are
- virtual and thus can be called automatically.
-
- */
-
-
- struct StreamableClassRecord {
- unsigned id;
- StreamablE (*load)(istream& is,
- StreamablE InstancE);
- StreamableClassRecord(unsigned id,
- StreamablE (*load)(istream& is,
- StreamablE InstancE))
- { this->id = id; this->load = load; }
- };
- typedef StreamableClassRecord * SCRecorD;
- #define SCRecorD0 ((SCRecorD)0)
-
- struct InstanceHoldingRecord {
- StreamablE InstancE;
- unsigned refCount, streamCount;
- long streamPos;
- InstanceHoldingRecord(StreamablE InstancE,
- unsigned refCount, long streamPos)
- {
- this->InstancE = InstancE;
- this->refCount = refCount;
- streamCount = 1;
- this->streamPos = streamPos;
- }
- };
- typedef InstanceHoldingRecord * IHRecorD;
- #define IHRecorD0 ((IHRecorD)0)
-
-
- class StreamableClassRegistry {
- Binder ClassRecords;
- Binder InstanceLinks;
- protected:
- virtual void error(char *msg, unsigned id = 0,
- StreamablE InstancE = StreamablE0);
- virtual void warn(char *msg, unsigned id = 0,
- StreamablE InstancE = StreamablE0);
- public:
- static int debug;
- StreamableClassRegistry()
- : ClassRecords(BDR_OK_FREE),
- InstanceLinks(BDR_OK_FREE)
- {}
- unsigned restream();
- void registerClass(unsigned id, StreamablE (*loader)
- (istream& is, StreamablE InstancE));
- void forgetClasses();
- istream& get(istream& is, StreamablE& InstancE);
- ostream& put(ostream& os, StreamablE InstancE);
- ~StreamableClassRegistry() { forgetClasses(); }
- };
-
- #define RestreamRegistry() SCRegistry.restream()
-
-
- inline istream& operator>>(istream& is, StreamablE& InstancE)
- {
- return SCRegistry.get(is,InstancE);
- }
-
- inline ostream& operator<<(ostream& os, StreamablE InstancE)
- {
- return SCRegistry.put(os, InstancE);
- }
-
-
-
- /*
-
- FncPtrRegistry is provided so that you can stream
- function pointers.
-
- */
-
- typedef void (*GenericFnC)();
- #define GenericFnC0 ((GenericFnC)0)
- #define ID_UnknownGenericFnC 0
-
- struct StreamableFncPtrRecord {
- unsigned id;
- GenericFnC fnC;
- StreamableFncPtrRecord(unsigned id,
- GenericFnC fnC)
- { this->id = id; this->fnC = fnC; }
- };
- typedef StreamableFncPtrRecord * SFPRecorD;
- #define SFPRecorD0 ((SFPRecorD)0)
-
- class StreamableFncPtrRegistry {
- Binder FncPtrRecords;
- public:
- static int debug;
- protected:
- virtual void error(char *msg, unsigned id);
- virtual void warn(char *msg, unsigned id);
- public:
- StreamableFncPtrRegistry() : FncPtrRecords() {}
- void registerFunction(unsigned id,
- GenericFnC fnC);
- GenericFnC FnC(unsigned id);
- unsigned ID(GenericFnC fnC);
- ~StreamableFncPtrRegistry()
- { FncPtrRecords.allFree(); }
- };
-
- #define SFPRegistry SFPReg
-
- extern StreamableFncPtrRegistry SFPRegistry;
-
- #define RegisterFunction(id, fnC) \
- SFPRegistry.registerFunction(id,fnC)
- #define FncPtrToID(fnC) \
- SFPRegistry.ID(fnC)
- #define IDtoFncPtr(id) \
- SFPRegistry.FnC(id)
-
-
- #endif
-